﻿/* 
* Copyright (c) 2010, The University of Texas at Austin
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, 
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, 
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, 
* this list of conditions and the following disclaimer in the documentation and/or other materials 
* provided with the distribution.
*
* Neither the name of The University of Texas at Austin nor the names of its contributors may be 
* used to endorse or promote products derived from this software without specific prior written 
* permission.
* 
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Bio.Data;
using Bio.Data.Interfaces;
using Bio.Data.Interfaces.Drawing;
using Bio.Views.Structure.Editor.Internal.Data;

namespace Bio.Views.Structure.Editor.Internal.Algorithms
{
    public class ExportDiagramToXRNA
    {
        public static void ExportDiagram(StructureModelData diagram, string targetFile)
        {
            if (diagram == null ||
                diagram.Entity == null ||
                diagram.Entity.Sequence == null ||
                diagram.Entity.BasePairs == null)
                throw new ArgumentException("Structure model incomplete or empty");

            StringWriter output = new StringWriter();

            //1. Build the pairing map
            Dictionary<int, IBasePairBioEntity> mappedBP = new Dictionary<int, IBasePairBioEntity>();
            for (int i = 0; i < diagram.Entity.Sequence.SequenceData.Count; i++)
                mappedBP.Add(i, null);

            foreach (var bp in diagram.Entity.BasePairs)
            {
                mappedBP[bp.FivePrimeIndex] = bp;
                mappedBP[bp.ThreePrimeIndex] = bp;
            }

            //2. Write out the rendering block
            SequenceRendering rendering = null;
            if (diagram.Entity.SequenceRenderingEdits != null)
            {
                rendering = diagram.Entity.SequenceRenderingEdits;
            }
            else
            {
                IExtensibleProperties diagramSequenceProps = diagram.Entity.Sequence as IExtensibleProperties;
                if (diagramSequenceProps != null &&
                diagramSequenceProps.DoesExtendedPropertyExist(SequenceMetadata.Key) &&
                diagramSequenceProps.GetExtendedProperty<SequenceMetadata>(SequenceMetadata.Key).Data.ContainsKey(SequenceRendering.Key))
                    rendering = (SequenceRendering)diagramSequenceProps.GetExtendedProperty<SequenceMetadata>(SequenceMetadata.Key).Data[SequenceRendering.Key];
            }

            for (int i = 0; i < diagram.Entity.Sequence.SequenceData.Count; i++)
            {
                double xpos = 0.0;
                double ypos = 0.0;

                if (rendering != null && rendering.RenderingMap.ContainsKey(i))
                {
                    xpos = rendering.RenderingMap[i].StartX;
                    ypos = rendering.RenderingMap[i].StartY * -1.0; //Flip cooridinate systems back for XRNA, down is now negative.
                }

                if (mappedBP[i] != null)
                {
                    if (i == mappedBP[i].FivePrimeIndex)
                    {
                        output.WriteLine(string.Format("{0} {1} {2:F2} {3:F2} 0 {4}", (i + 1), diagram.Entity.Sequence.SequenceData[i].Value, xpos, ypos, (mappedBP[i].ThreePrimeIndex + 1)));
                    }
                    else
                    {
                        output.WriteLine(string.Format("{0} {1} {2:F2} {3:F2} 0 {4}", (i + 1), diagram.Entity.Sequence.SequenceData[i].Value, xpos, ypos, (mappedBP[i].FivePrimeIndex + 1)));
                    }
                }
                else
                {
                    output.WriteLine(string.Format("{0} {1} {2:F2} {3:F2} 0 0", (i + 1), diagram.Entity.Sequence.SequenceData[i].Value, xpos, ypos));
                }
            }

            //3. Check if we have a global font specifier. If not, we write a default one and then we have to check all the nucleotide metadata.
            string defaultFontSpecification = null;

            StructureModelMetadata structureModelMetadata = null;
            if (diagram.Entity.StructureModelPropertyEdits != null)
                structureModelMetadata = diagram.Entity.StructureModelPropertyEdits;
            else
                structureModelMetadata = diagram.Entity.StructureModelProperties;

            if (structureModelMetadata != null)
            {
                if (structureModelMetadata.NucleotideTextRendering != null)
                {
                    defaultFontSpecification = string.Format("1-{0}{1}", diagram.Entity.Sequence.SequenceData.Count, ToXRNADefaultFontSpecification(structureModelMetadata.NucleotideTextRendering));
                }
                else
                {
                    defaultFontSpecification = string.Format("1-{0}{1}", diagram.Entity.Sequence.SequenceData.Count, ToXRNADefaultFontSpecification(null));
                }
            }
            else
            {
                defaultFontSpecification = string.Format("1-{0}{1}", diagram.Entity.Sequence.SequenceData.Count, ToXRNADefaultFontSpecification(null));
            }

            Dictionary<string, List<int>> ntFormattingMap = new Dictionary<string, List<int>>();

            //4. Format any base pair connectors.
            Dictionary<string, List<int>> bpConnMap = new Dictionary<string, List<int>>();
            bpConnMap.Add(XRNA_HIDDEN_CONNECTOR_DEFINITION, new List<int>());
            foreach (var pair in diagram.Entity.BasePairs)
            {
                IExtensibleProperties pairProps = pair as IExtensibleProperties;
                if (pairProps != null)
                {
                    BasePairMetadata bpMetadata = null;
                    if (diagram.Entity.BasePairPropertyEdits.ContainsKey(pair.FivePrimeIndex))
                    {
                        bpMetadata = diagram.Entity.BasePairPropertyEdits[pair.FivePrimeIndex];
                    }
                    else
                    {
                        if(pairProps.DoesExtendedPropertyExist(BasePairMetadata.Key))
                            bpMetadata = pairProps.GetExtendedProperty<BasePairMetadata>(BasePairMetadata.Key);
                    }
                    
                    if (bpMetadata != null)
                    {
                        if (bpMetadata.ConnectorVisible.HasValue && !bpMetadata.ConnectorVisible.Value)
                        {
                            bpConnMap[XRNA_HIDDEN_CONNECTOR_DEFINITION].Add((pair.FivePrimeIndex + 1));
                        }
                        else
                        {
                            string connectorFormat = ToXRNAConnectorSpecification(bpMetadata.ConnectorRendering, bpMetadata.ConnectorStyle);
                            if (connectorFormat != null)
                            {
                                if (!bpConnMap.ContainsKey(connectorFormat))
                                    bpConnMap.Add(connectorFormat, new List<int>());    
                                
                                bpConnMap[connectorFormat].Add((pair.FivePrimeIndex + 1));
                            }
                        }

                        if (bpMetadata.NucleotideRenderingProperties != null)
                        {
                            NucleotideMetadata ntMetadata = bpMetadata.NucleotideRenderingProperties;
                            if (ntMetadata != null)
                            {
                                if (ntMetadata.Visible.HasValue && !ntMetadata.Visible.Value)
                                {
                                    ntFormattingMap[XRNA_HIDDEN_NT_DEFINITION].Add((pair.FivePrimeIndex + 1));
                                    ntFormattingMap[XRNA_HIDDEN_NT_DEFINITION].Add((pair.ThreePrimeIndex + 1));
                                }

                                //We look to export text rendering first.
                                if (ntMetadata.TextRendering != null || (ntMetadata.Style.HasValue && ntMetadata.Style.Value == NucleotideMetadata.RenderingMode.Text))
                                {
                                    string textFormat = null;
                                    if (ntMetadata != null)
                                    {
                                        if (ntMetadata.IsSubstituted)
                                            textFormat = ToXRNANucleotideTextSubstitution(ntMetadata.TextRendering, ntMetadata.SubstitutionCharacter);
                                        else
                                            textFormat = ToXRNADefaultFontSpecification(ntMetadata.TextRendering);
                                    }
                                    else
                                    {
                                        textFormat = ToXRNADefaultFontSpecification(null);
                                    }

                                    if (textFormat != null)
                                    {
                                        if (!ntFormattingMap.ContainsKey(textFormat))
                                            ntFormattingMap.Add(textFormat, new List<int>());

                                        ntFormattingMap[textFormat].Add((pair.FivePrimeIndex + 1));
                                        ntFormattingMap[textFormat].Add((pair.ThreePrimeIndex + 1));
                                    }
                                }
                                else if (ntMetadata.CircleRendering != null || (ntMetadata.Style.HasValue && ntMetadata.Style.Value == NucleotideMetadata.RenderingMode.Circle))
                                {
                                    string circleFormat = ToXRNANucleotideCircleSubstitution(ntMetadata.CircleRendering);
                                    if (circleFormat != null)
                                    {
                                        if (!ntFormattingMap.ContainsKey(circleFormat))
                                            ntFormattingMap.Add(circleFormat, new List<int>());

                                        ntFormattingMap[circleFormat].Add((pair.FivePrimeIndex + 1));
                                        ntFormattingMap[circleFormat].Add((pair.ThreePrimeIndex + 1));
                                    }
                                }
                            }
                        }
                    }
                }
            }

            //5. Format any individual nucleotides.
            ntFormattingMap.Add(XRNA_HIDDEN_NT_DEFINITION, new List<int>());
            for(int i=0; i < diagram.Entity.Sequence.SequenceData.Count; i++)
            {
                var nt = diagram.Entity.Sequence.SequenceData[i];
                IExtensibleProperties ntProps = nt as IExtensibleProperties;
                if (ntProps != null)
                {
                    NucleotideMetadata ntMetadata = null;
                    if (diagram.Entity.NucleotidePropertyEdits.ContainsKey(i))
                    {
                        ntMetadata = diagram.Entity.NucleotidePropertyEdits[i];
                    }
                    else
                    {
                        if (ntProps.DoesExtendedPropertyExist(NucleotideMetadata.Key))
                            ntMetadata = ntProps.GetExtendedProperty<NucleotideMetadata>(NucleotideMetadata.Key);
                    }
                    
                    if (ntMetadata != null)
                    {
                        if (ntMetadata.Visible.HasValue && !ntMetadata.Visible.Value)
                            ntFormattingMap[XRNA_HIDDEN_NT_DEFINITION].Add((i + 1));

                        //We look to export text rendering first.
                        if (ntMetadata.TextRendering != null || (ntMetadata.Style.HasValue && ntMetadata.Style.Value == NucleotideMetadata.RenderingMode.Text))
                        {
                            string textFormat = null;
                            if (ntMetadata != null)
                            {
                                if (ntMetadata.IsSubstituted)
                                    textFormat = ToXRNANucleotideTextSubstitution(ntMetadata.TextRendering, ntMetadata.SubstitutionCharacter);
                                else
                                    textFormat = ToXRNADefaultFontSpecification(ntMetadata.TextRendering);
                            }
                            else
                            {
                                textFormat = ToXRNADefaultFontSpecification(null);
                            }
                            
                            if (textFormat != null)
                            {
                                if (!ntFormattingMap.ContainsKey(textFormat))
                                    ntFormattingMap.Add(textFormat, new List<int>());

                                ntFormattingMap[textFormat].Add((i + 1));
                            }       
                        }
                        else if (ntMetadata.CircleRendering != null || (ntMetadata.Style.HasValue && ntMetadata.Style.Value == NucleotideMetadata.RenderingMode.Circle))
                        {
                            string circleFormat = ToXRNANucleotideCircleSubstitution(ntMetadata.CircleRendering);
                            if (circleFormat != null)
                            {
                                if (!ntFormattingMap.ContainsKey(circleFormat))
                                    ntFormattingMap.Add(circleFormat, new List<int>());

                                ntFormattingMap[circleFormat].Add((i + 1));
                            }
                        }
                    } 
                }
            }

            //6. Write the output file.
            //6a. Write the default font specification.
            output.WriteLine(defaultFontSpecification);
            
            //6b. Write any text modifications
            foreach (var textSpecification in ntFormattingMap.Keys)
            {
                if (ntFormattingMap[textSpecification] != null && ntFormattingMap[textSpecification].Count > 0 && !textSpecification.Equals(XRNA_HIDDEN_NT_DEFINITION))
                {
                    StringBuilder finalTextSpecification = new StringBuilder(textSpecification);
                    bool bFirstNtWithSpec = true;
                    foreach (var specdnt in ntFormattingMap[textSpecification])
                    {
                        if (!bFirstNtWithSpec)
                            finalTextSpecification.Insert(0, ",");

                        finalTextSpecification.Insert(0, specdnt);

                        if (bFirstNtWithSpec)
                            bFirstNtWithSpec = false;
                    }
                    output.WriteLine(finalTextSpecification.ToString());
                }
            }

            //6c. Write out any alternate connector specifications
            foreach (var connSpecification in bpConnMap.Keys)
            {
                if (bpConnMap[connSpecification] != null && bpConnMap[connSpecification].Count > 0)
                {
                    StringBuilder finalConnSpecification = new StringBuilder(connSpecification);
                    finalConnSpecification.Insert(0, " ");
                    bool bFirstBPWithSpec = true;
                    foreach (var specdbp in bpConnMap[connSpecification])
                    {
                        if (!bFirstBPWithSpec)
                            finalConnSpecification.Insert(0, ",");

                        finalConnSpecification.Insert(0, specdbp);

                        if (bFirstBPWithSpec)
                            bFirstBPWithSpec = false;
                    }
                    output.WriteLine(finalConnSpecification.ToString());
                }
            }
            
            //6d. Write out and hidden nucleotides
            if (ntFormattingMap.ContainsKey(XRNA_HIDDEN_NT_DEFINITION) && ntFormattingMap[XRNA_HIDDEN_NT_DEFINITION].Count > 0)
            {
                StringBuilder hiddenRanges = new StringBuilder(XRNA_HIDDEN_NT_DEFINITION);
                var hiddenNtOrdered = ntFormattingMap[XRNA_HIDDEN_NT_DEFINITION].OrderBy(idx => idx);
                int rangeStart = 0;
                int rangeEnd = 0;
                foreach (var idx in hiddenNtOrdered)
                {
                    if (rangeStart == 0)
                    {
                        rangeStart = idx;
                        rangeEnd = idx;
                        continue;
                    }

                    if (idx == rangeEnd + 1)
                    {
                        //Were still building the range
                        rangeEnd = idx;
                        continue;
                    }
                    else
                    {
                        //Discontinuous, starting a new range
                        hiddenRanges.Append(string.Format(" {0} {1}", rangeStart, rangeEnd));
                        rangeStart = idx;
                        rangeEnd = idx;
                    }
                }

                //Check if we have a final range to append
                if (rangeStart > 0 && rangeEnd > 0)
                    hiddenRanges.Append(string.Format(" {0} {1}", rangeStart, rangeEnd));

                output.WriteLine(hiddenRanges.ToString());
            }

            output.Flush();
            File.WriteAllText(targetFile, output.ToString());
        }

        static ExportDiagramToXRNA()
        {
            XRNAFONTMAP = new List<Tuple<string,string,string,int>>();
            XRNAFONTMAP.Add(new Tuple<string,string,string,int>(XRNAFONT_HELVETICA_ARIAL_FAMILY, "Normal", "Regular", 0));
            XRNAFONTMAP.Add(new Tuple<string,string,string,int>(XRNAFONT_HELVETICA_ARIAL_FAMILY, "Oblique", "Regular", 1));
            XRNAFONTMAP.Add(new Tuple<string,string,string,int>(XRNAFONT_HELVETICA_ARIAL_FAMILY, "Normal", "Bold", 2));
            XRNAFONTMAP.Add(new Tuple<string,string,string,int>(XRNAFONT_HELVETICA_ARIAL_FAMILY, "Oblique", "Bold", 3));
            XRNAFONTMAP.Add(new Tuple<string,string,string,int>(XRNAFONT_TIMES_TIMESNEWROMAN_FAMILY, "Normal", "Regular", 4));
            XRNAFONTMAP.Add(new Tuple<string,string,string,int>(XRNAFONT_TIMES_TIMESNEWROMAN_FAMILY, "Italic", "Regular", 5));
            XRNAFONTMAP.Add(new Tuple<string,string,string,int>(XRNAFONT_TIMES_TIMESNEWROMAN_FAMILY, "Normal", "Bold", 6));
            XRNAFONTMAP.Add(new Tuple<string,string,string,int>(XRNAFONT_TIMES_TIMESNEWROMAN_FAMILY, "Italic", "Bold", 7));
            XRNAFONTMAP.Add(new Tuple<string,string,string,int>(XRNAFONT_COURIER_COURIERNEW_FAMILY, "Normal", "Regular", 8));
            XRNAFONTMAP.Add(new Tuple<string,string,string,int>(XRNAFONT_COURIER_COURIERNEW_FAMILY, "Oblique", "Regular", 9));
            XRNAFONTMAP.Add(new Tuple<string,string,string,int>(XRNAFONT_COURIER_COURIERNEW_FAMILY, "Normal", "Bold", 10));
            XRNAFONTMAP.Add(new Tuple<string,string,string,int>(XRNAFONT_COURIER_COURIERNEW_FAMILY, "Oblique", "Bold", 11));
            XRNAFONTMAP.Add(new Tuple<string,string,string,int>("Symbol", "Normal", "Regular", 13));
        }

        private static List<Tuple<string, string, string, int>> XRNAFONTMAP;
        private static string XRNAFONT_HELVETICA_ARIAL_FAMILY = "Arial";
        private static string XRNAFONT_COURIER_COURIERNEW_FAMILY = "Courier, Courier New";
        private static string XRNAFONT_TIMES_TIMESNEWROMAN_FAMILY = "Times, Times New Roman";
        private static string XRNA_HIDDEN_CONNECTOR_DEFINITION = "#!Bn";
        private static string XRNA_HIDDEN_NT_DEFINITION = "#! h";


        private static string ToXRNAConnectorSpecification(IBasePairConnectorShape shape, BasePairMetadata.ConnectorRenderingMode? renderingStyle)
        {
            if (shape == null)
            {
                if (renderingStyle.HasValue && renderingStyle.Value == BasePairMetadata.ConnectorRenderingMode.Circle)
                {
                    //#!Bc 0.00 360.00 {radius} {edge thickness} {filled} {fill color}
                    return string.Format("#!Bc 0.00 360.00 {0:F2} {1:F2} {2} {3}", 2.0, 0, 0, 0);
                }
                else
                {
                    return null; //Pickup the default XRNA line rendering.
                }
            }
            else
            {
                if (renderingStyle.HasValue && renderingStyle.Value == BasePairMetadata.ConnectorRenderingMode.Circle)
                {
                    int filled = (shape.Filled.HasValue && shape.Filled.Value) ? 0 : 1;

                    string color = "0";
                    if (!string.IsNullOrEmpty(shape.FillColor))
                    {
                        color = shape.FillColor.Substring(1);
                    }

                    double radius = 2.0;
                    if (shape.Size > 0.0)
                        radius = shape.Size / 2.0;

                    //#!Bc 0.00 360.00 {radius} {edge thickness} {filled} {fill color}
                    return string.Format("#!Bc 0.00 360.00 {0:F2} {1:F2} {2} {3}", radius, shape.EdgeThickness, filled, color);
                }
                else
                {
                    double thickness = 1.0;
                    if (shape.EdgeThickness > 0.0)
                        thickness = shape.EdgeThickness;

                    string color = "0";
                    if (!string.IsNullOrEmpty(shape.StrokeColor))
                    {
                        color = shape.StrokeColor.Substring(1);
                    }

                    //#Bl {thickness} {color}.....
                    return string.Format("#!Bl {0:F2} {1} 1 0 0 0 0", thickness, color);
                }
            }
        }

        private static string ToXRNADefaultFontSpecification(ITextShape shape)
        {
            if (shape == null)
                return "#!s 8 0 0";

            int xrnaTypefaceCode = ToXRNATypefaceCode(shape.Font, shape.FontStyle, shape.FontWeight);
            
            string color = "0";
            if (!string.IsNullOrEmpty(shape.Color))
            {
                color = shape.Color.Substring(1);
            }

            double fontSize = 8.0;
            if (shape.FontSize > 0.0)
            {
                fontSize = shape.FontSize;
            }

            //#!s {font size} {font typeface} {RGB color}
            return string.Format("#!s {0:F1} {1} {2}", fontSize, xrnaTypefaceCode, color);
        }


        private static string ToXRNANucleotideTextSubstitution(ITextShape shape, char substitutionChar)
        {
            int xrnaTypefaceCode = 0;
            if (shape != null)
            {
                xrnaTypefaceCode = ToXRNATypefaceCode(shape.Font, shape.FontStyle, shape.FontWeight);
            }

            string color = "0";
            if (shape != null && !string.IsNullOrEmpty(shape.Color))
            {
                color = shape.Color.Substring(1);
            }

            double fontSize = 12.0;
            if (shape != null && shape.FontSize > 0.0)
            {
                fontSize = shape.FontSize;
            }
            
            if(xrnaTypefaceCode==13)
                //#!S {font size} {substitution char} {RGB color}
                return string.Format("#!S {0:F1} {1} {2}", fontSize, substitutionChar, color);
            else
                //#!C {font size} {font typeface} {substitution char} {RGB color}
                return string.Format("#!C {0:F1} {1} {2} {3}", fontSize, xrnaTypefaceCode, substitutionChar, color);
        }

        private static string ToXRNANucleotideCircleSubstitution(ICircleShape shape)
        {
            if (shape == null)
                return string.Format("#!c 0.00 360.00 {0:F2} {1:F2} {2} {3}", 1.5, 0, 0, 0);

            double radius = 2.0;
            if (shape != null && shape.Diameter > 0.0)
                radius = shape.Diameter / 2.0;

            double edgeThickness = 0.0;
            if (shape != null && shape.EdgeThickness > 0.0)
                edgeThickness = shape.EdgeThickness;

            string fillColor = "0";
            if (shape != null && !string.IsNullOrEmpty(shape.FillColor))
            {
                fillColor = shape.FillColor.Substring(1);
            }

            int filled = 1;
            if (shape != null && shape.Filled.HasValue && shape.Filled.Value)
                filled = 0;

            //#!c 0.00 360.00 {radius} {edge thickness} {filled} {color}
            return string.Format("#!c 0.00 360.00 {0:F2} {1:F2} {2} {3}", radius, edgeThickness, filled, fillColor);
        }

        private static int ToXRNATypefaceCode(string font, string fontStyle, string fontWeight)
        {
            string fontStyleInternal = "Normal";
            string fontWeightInternal = "Regular";

            if (fontStyle != null)
                fontStyleInternal = fontStyle;

            //Since XRNA only supports Regular or Bold font weights, this will unfortunately be lossy.
            if (fontWeight != null && (fontWeight.Equals("Bold") || fontWeight.Equals("Regular")))
                fontWeightInternal = fontWeight;

            if (font != null && !font.ToString().Equals(string.Empty))
            {
                string[] fonts = Regex.Split(font, ",");
                foreach (var fontname in fonts)
                {
                    var fontnametrimmed = fontname.Trim();
                    if (fontnametrimmed.Equals("Helvetica") || fontnametrimmed.Equals("Arial"))
                    {
                        var matchingXRNAFontTuple = XRNAFONTMAP.Where(xrnafont => xrnafont.Item1.Equals(XRNAFONT_HELVETICA_ARIAL_FAMILY) && xrnafont.Item2.Equals(fontStyleInternal) && xrnafont.Item3.Equals(fontWeightInternal)).FirstOrDefault();
                        if (matchingXRNAFontTuple != null)
                            return matchingXRNAFontTuple.Item4;
                    }
                    else if (fontnametrimmed.Equals("Times") || fontnametrimmed.Equals("Times New Roman"))
                    {
                        var matchingXRNAFontTuple = XRNAFONTMAP.Where(xrnafont => xrnafont.Item1.Equals(XRNAFONT_TIMES_TIMESNEWROMAN_FAMILY) && xrnafont.Item2.Equals(fontStyleInternal) && xrnafont.Item3.Equals(fontWeightInternal)).FirstOrDefault();
                        if (matchingXRNAFontTuple != null)
                            return matchingXRNAFontTuple.Item4;
                    }
                    else if (fontnametrimmed.Equals("Courier") || fontnametrimmed.Equals("Courier New"))
                    {
                        var matchingXRNAFontTuple = XRNAFONTMAP.Where(xrnafont => xrnafont.Item1.Equals(XRNAFONT_COURIER_COURIERNEW_FAMILY) && xrnafont.Item2.Equals(fontStyleInternal) && xrnafont.Item3.Equals(fontWeightInternal)).FirstOrDefault();
                        if (matchingXRNAFontTuple != null)
                            return matchingXRNAFontTuple.Item4;
                    }
                    else if (fontnametrimmed.Equals("Symbol"))
                    {
                        var matchingXRNAFontTuple = XRNAFONTMAP.Where(xrnafont => xrnafont.Item1.Equals("Symbol") && xrnafont.Item2.Equals(fontStyleInternal) && xrnafont.Item3.Equals(fontWeightInternal)).FirstOrDefault();
                        if (matchingXRNAFontTuple != null)
                            return matchingXRNAFontTuple.Item4;
                    }
                }
            }
            return 0; //We default to XRNA font typeface 0
        }
    }
}
